package com.base.components.database.mybatis.service;

import com.base.components.common.db.dialect.PaginationDialect;
import com.github.pagehelper.Page;
import com.github.pagehelper.autoconfigure.PageHelperProperties;
import org.springframework.dao.DataAccessException;
import org.springframework.jdbc.core.BatchPreparedStatementSetter;
import org.springframework.jdbc.core.CallableStatementCallback;
import org.springframework.jdbc.core.CallableStatementCreator;
import org.springframework.jdbc.core.ConnectionCallback;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.ParameterizedPreparedStatementSetter;
import org.springframework.jdbc.core.PreparedStatementCallback;
import org.springframework.jdbc.core.PreparedStatementCreator;
import org.springframework.jdbc.core.PreparedStatementSetter;
import org.springframework.jdbc.core.ResultSetExtractor;
import org.springframework.jdbc.core.RowCallbackHandler;
import org.springframework.jdbc.core.RowMapper;
import org.springframework.jdbc.core.StatementCallback;
import org.springframework.jdbc.support.KeyHolder;
import org.springframework.jdbc.support.rowset.SqlRowSet;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;

import java.util.Collection;
import java.util.List;
import java.util.Map;

/**
 * PaginationJdbcTemplate
 *
 * @author <a href="drakelee1221@gmail.com">LiGeng</a>
 * @version v1.0.0
 * @date 2019-01-23 15:42
 */
public class PaginationJdbcTemplate{
  private JdbcTemplate jdbcTemplate;
  private PaginationDialect.PageSqlBuilder pageSqlBuilder;

  public PaginationJdbcTemplate(PageHelperProperties pageHelperProperties, JdbcTemplate jdbcTemplate) {
    this.pageSqlBuilder = PaginationDialect.getPageSqlBuilder(pageHelperProperties.getHelperDialect());
    Assert.notNull(this.pageSqlBuilder, "需设置 pagehelper.helperDialect 数据库类别");
    this.jdbcTemplate = jdbcTemplate;
  }
  public PaginationJdbcTemplate(String dbName, JdbcTemplate jdbcTemplate) {
    dbName = dbName.toLowerCase();
    this.pageSqlBuilder = PaginationDialect.getPageSqlBuilder(dbName);
    Assert.notNull(this.pageSqlBuilder, "未匹配数据库类别" + dbName);
    this.jdbcTemplate = jdbcTemplate;
  }

  public String getPageSql(String sql, Page page){
    return pageSqlBuilder.getPageSql(sql, page);
  }

  @Nullable
  public <T> T execute(ConnectionCallback<T> action) throws DataAccessException {
    return jdbcTemplate.execute(action);
  }

  @Nullable
  public <T> T execute(StatementCallback<T> action) throws DataAccessException {
    return jdbcTemplate.execute(action);
  }

  public void execute(String sql) throws DataAccessException {
    jdbcTemplate.execute(sql);
  }

  @Nullable
  public <T> T query(String sql, ResultSetExtractor<T> rse) throws DataAccessException {
    return jdbcTemplate.query(sql, rse);
  }

  public void query(String sql, RowCallbackHandler rch) throws DataAccessException {
    jdbcTemplate.query(sql, rch);
  }

  public <T> List<T> query(String sql, RowMapper<T> rowMapper) throws DataAccessException {
    return jdbcTemplate.query(sql, rowMapper);
  }

  public Map<String, Object> queryForMap(String sql) throws DataAccessException {
    return jdbcTemplate.queryForMap(sql);
  }

  @Nullable
  public <T> T queryForObject(String sql, RowMapper<T> rowMapper) throws DataAccessException {
    return jdbcTemplate.queryForObject(sql, rowMapper);
  }

  @Nullable
  public <T> T queryForObject(String sql, Class<T> requiredType) throws DataAccessException {
    return jdbcTemplate.queryForObject(sql, requiredType);
  }

  public <T> List<T> queryForList(String sql, Class<T> elementType) throws DataAccessException {
    return jdbcTemplate.queryForList(sql, elementType);
  }

  public List<Map<String, Object>> queryForList(String sql) throws DataAccessException {
    return jdbcTemplate.queryForList(sql);
  }

  public SqlRowSet queryForRowSet(String sql) throws DataAccessException {
    return jdbcTemplate.queryForRowSet(sql);
  }

  public int update(String sql) throws DataAccessException {
    return jdbcTemplate.update(sql);
  }

  public int[] batchUpdate(String... sql) throws DataAccessException {
    return jdbcTemplate.batchUpdate(sql);
  }

  @Nullable
  public <T> T execute(PreparedStatementCreator psc, PreparedStatementCallback<T> action) throws DataAccessException {
    return jdbcTemplate.execute(psc, action);
  }

  @Nullable
  public <T> T execute(String sql, PreparedStatementCallback<T> action) throws DataAccessException {
    return jdbcTemplate.execute(sql, action);
  }

  /**
   * Query using a prepared statement, allowing for a PreparedStatementCreator
   * and a PreparedStatementSetter. Most other query methods use this method,
   * but application code will always work with either a creator or a setter.
   * @param psc Callback handler that can create a PreparedStatement given a
   * Connection
   * @param pss object that knows how to set values on the prepared statement.
   * If this is null, the SQL will be assumed to contain no bind parameters.
   * @param rse object that will extract results.
   * @return an arbitrary result object, as returned by the ResultSetExtractor
   * @throws DataAccessException if there is any problem
   */
  @Nullable
  public <T> T query(PreparedStatementCreator psc, PreparedStatementSetter pss, ResultSetExtractor<T> rse)
    throws DataAccessException {
    return jdbcTemplate.query(psc, pss, rse);
  }

  @Nullable
  public <T> T query(PreparedStatementCreator psc, ResultSetExtractor<T> rse) throws DataAccessException {
    return jdbcTemplate.query(psc, rse);
  }

  @Nullable
  public <T> T query(String sql, PreparedStatementSetter pss, ResultSetExtractor<T> rse) throws DataAccessException {
    return jdbcTemplate.query(sql, pss, rse);
  }

  @Nullable
  public <T> T query(String sql, Object[] args, int[] argTypes, ResultSetExtractor<T> rse) throws DataAccessException {
    return jdbcTemplate.query(sql, args, argTypes, rse);
  }

  @Nullable
  public <T> T query(String sql, Object[] args, ResultSetExtractor<T> rse) throws DataAccessException {
    return jdbcTemplate.query(sql, args, rse);
  }

  @Nullable
  public <T> T query(String sql, ResultSetExtractor<T> rse, Object... args) throws DataAccessException {
    return jdbcTemplate.query(sql, rse, args);
  }

  public void query(PreparedStatementCreator psc, RowCallbackHandler rch) throws DataAccessException {
    jdbcTemplate.query(psc, rch);
  }

  public void query(String sql, PreparedStatementSetter pss, RowCallbackHandler rch) throws DataAccessException {
    jdbcTemplate.query(sql, pss, rch);
  }

  public void query(String sql, Object[] args, int[] argTypes, RowCallbackHandler rch) throws DataAccessException {
    jdbcTemplate.query(sql, args, argTypes, rch);
  }

  public void query(String sql, Object[] args, RowCallbackHandler rch) throws DataAccessException {
    jdbcTemplate.query(sql, args, rch);
  }

  public void query(String sql, RowCallbackHandler rch, Object... args) throws DataAccessException {
    jdbcTemplate.query(sql, rch, args);
  }

  public <T> List<T> query(PreparedStatementCreator psc, RowMapper<T> rowMapper) throws DataAccessException {
    return jdbcTemplate.query(psc, rowMapper);
  }

  public <T> List<T> query(String sql, PreparedStatementSetter pss, RowMapper<T> rowMapper) throws DataAccessException {
    return jdbcTemplate.query(sql, pss, rowMapper);
  }

  public <T> List<T> query(String sql, Object[] args, int[] argTypes, RowMapper<T> rowMapper)
    throws DataAccessException {
    return jdbcTemplate.query(sql, args, argTypes, rowMapper);
  }

  public <T> List<T> query(String sql, Object[] args, RowMapper<T> rowMapper) throws DataAccessException {
    return jdbcTemplate.query(sql, args, rowMapper);
  }

  public <T> List<T> query(String sql, RowMapper<T> rowMapper, Object... args) throws DataAccessException {
    return jdbcTemplate.query(sql, rowMapper, args);
  }

  @Nullable
  public <T> T queryForObject(String sql, Object[] args, int[] argTypes, RowMapper<T> rowMapper)
    throws DataAccessException {
    return jdbcTemplate.queryForObject(sql, args, argTypes, rowMapper);
  }

  @Nullable
  public <T> T queryForObject(String sql, Object[] args, RowMapper<T> rowMapper) throws DataAccessException {
    return jdbcTemplate.queryForObject(sql, args, rowMapper);
  }

  @Nullable
  public <T> T queryForObject(String sql, RowMapper<T> rowMapper, Object... args) throws DataAccessException {
    return jdbcTemplate.queryForObject(sql, rowMapper, args);
  }

  @Nullable
  public <T> T queryForObject(String sql, Object[] args, int[] argTypes, Class<T> requiredType)
    throws DataAccessException {
    return jdbcTemplate.queryForObject(sql, args, argTypes, requiredType);
  }

  public <T> T queryForObject(String sql, Object[] args, Class<T> requiredType) throws DataAccessException {
    return jdbcTemplate.queryForObject(sql, args, requiredType);
  }

  public <T> T queryForObject(String sql, Class<T> requiredType, Object... args) throws DataAccessException {
    return jdbcTemplate.queryForObject(sql, requiredType, args);
  }

  public Map<String, Object> queryForMap(String sql, Object[] args, int[] argTypes) throws DataAccessException {
    return jdbcTemplate.queryForMap(sql, args, argTypes);
  }

  public Map<String, Object> queryForMap(String sql, Object... args) throws DataAccessException {
    return jdbcTemplate.queryForMap(sql, args);
  }

  public <T> List<T> queryForList(String sql, Object[] args, int[] argTypes, Class<T> elementType)
    throws DataAccessException {
    return jdbcTemplate.queryForList(sql, args, argTypes, elementType);
  }

  public <T> List<T> queryForList(String sql, Object[] args, Class<T> elementType) throws DataAccessException {
    return jdbcTemplate.queryForList(sql, args, elementType);
  }

  public <T> List<T> queryForList(String sql, Class<T> elementType, Object... args) throws DataAccessException {
    return jdbcTemplate.queryForList(sql, elementType, args);
  }

  public List<Map<String, Object>> queryForList(String sql, Object[] args, int[] argTypes) throws DataAccessException {
    return jdbcTemplate.queryForList(sql, args, argTypes);
  }

  public List<Map<String, Object>> queryForList(String sql, Object... args) throws DataAccessException {
    return jdbcTemplate.queryForList(sql, args);
  }

  public SqlRowSet queryForRowSet(String sql, Object[] args, int[] argTypes) throws DataAccessException {
    return jdbcTemplate.queryForRowSet(sql, args, argTypes);
  }

  public SqlRowSet queryForRowSet(String sql, Object... args) throws DataAccessException {
    return jdbcTemplate.queryForRowSet(sql, args);
  }

  public int update(PreparedStatementCreator psc) throws DataAccessException {
    return jdbcTemplate.update(psc);
  }

  public int update(PreparedStatementCreator psc, KeyHolder generatedKeyHolder) throws DataAccessException {
    return jdbcTemplate.update(psc, generatedKeyHolder);
  }

  public int update(String sql, PreparedStatementSetter pss) throws DataAccessException {
    return jdbcTemplate.update(sql, pss);
  }

  public int update(String sql, Object[] args, int[] argTypes) throws DataAccessException {
    return jdbcTemplate.update(sql, args, argTypes);
  }

  public int update(String sql, Object... args) throws DataAccessException {
    return jdbcTemplate.update(sql, args);
  }

  public int[] batchUpdate(String sql, BatchPreparedStatementSetter pss) throws DataAccessException {
    return jdbcTemplate.batchUpdate(sql, pss);
  }

  public int[] batchUpdate(String sql, List<Object[]> batchArgs) throws DataAccessException {
    return jdbcTemplate.batchUpdate(sql, batchArgs);
  }

  public int[] batchUpdate(String sql, List<Object[]> batchArgs, int[] argTypes) throws DataAccessException {
    return jdbcTemplate.batchUpdate(sql, batchArgs, argTypes);
  }

  public <T> int[][] batchUpdate(String sql, Collection<T> batchArgs, int batchSize,
                                 ParameterizedPreparedStatementSetter<T> pss) throws DataAccessException {
    return jdbcTemplate.batchUpdate(sql, batchArgs, batchSize, pss);
  }

  @Nullable
  public <T> T execute(CallableStatementCreator csc, CallableStatementCallback<T> action) throws DataAccessException {
    return jdbcTemplate.execute(csc, action);
  }

  @Nullable
  public <T> T execute(String callString, CallableStatementCallback<T> action) throws DataAccessException {
    return jdbcTemplate.execute(callString, action);
  }
}
